package com.socket.tools.service;

import com.socket.tools.model.Message;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 连接管理器
 * 管理客户端连接队列和服务端用户管理
 */
@Service
public class ConnectionManager {
    
    // 服务端用户会话映射 (服务端用户ID -> WebSocket会话)
    private final Map<String, WebSocketSession> adminSessions = new ConcurrentHashMap<>();
    
    // 客户端会话映射 (客户端会话ID -> WebSocket会话)
    private final Map<String, WebSocketSession> clientSessions = new ConcurrentHashMap<>();
    
    // 连接请求队列 (等待服务端用户处理的客户端请求)
    private final Queue<ConnectionRequest> connectionQueue = new ConcurrentLinkedQueue<>();
    
    // 活跃连接映射 (服务端用户ID -> 客户端会话ID)
    private final Map<String, String> activeConnections = new ConcurrentHashMap<>();
    
    // 反向映射 (客户端会话ID -> 服务端用户ID)
    private final Map<String, String> clientToAdmin = new ConcurrentHashMap<>();

    //客户端连接时间记录 todo 可用于数据库存储客户端连接时间 根据情况优化，或者定时清理
    private final Map<String, String> clientConnectTime = new ConcurrentHashMap<>();


    // 统计信息
    private final AtomicInteger totalRequests = new AtomicInteger(0);
    private final AtomicInteger acceptedRequests = new AtomicInteger(0);
    private final AtomicInteger rejectedRequests = new AtomicInteger(0);
    
    // 连接池管理
    private final Map<String, Long> adminLastActivity = new ConcurrentHashMap<>();
    private final AtomicInteger maxConcurrentConnections = new AtomicInteger(0);
    private final AtomicInteger totalConnections = new AtomicInteger(0);
    
    // 负载均衡相关
    private final Queue<String> availableAdmins = new ConcurrentLinkedQueue<>();
    private final Map<String, Integer> adminLoad = new ConcurrentHashMap<>();

    //终端号和sessionid的匹配，服务前端用于删除缓存storage数据
    private final Map<String, String> terminalAndSessionMap = new ConcurrentHashMap<>();
    
    /**
     * 连接请求内部类
     */
    public static class ConnectionRequest {
        private final String clientSessionId;
        private final String clientName;
        private final long requestTime;
        private final WebSocketSession clientSession;
        
        public ConnectionRequest(String clientSessionId, String clientName, WebSocketSession clientSession) {
            this.clientSessionId = clientSessionId;
            this.clientName = clientName;
            this.requestTime = System.currentTimeMillis();
            this.clientSession = clientSession;
        }
        
        // Getters
        public String getClientSessionId() { return clientSessionId; }
        public String getClientName() { return clientName; }
        public long getRequestTime() { return requestTime; }
        public WebSocketSession getClientSession() { return clientSession; }
    }
    
    /**
     * 注册服务端用户
     */
    public void registerAdmin(String adminId, WebSocketSession session) {
        adminSessions.put(adminId, session);
        broadcastToAdmins(new Message(Message.MessageType.SYSTEM_MESSAGE, "系统", 
                "服务端用户 " + adminId + " 已上线"));
        
        // 广播在线管理员更新
        broadcastOnlineAdminsUpdate();
        
        logStatus();
    }
    
    /**
     * 注销服务端用户
     */
    public void unregisterAdmin(String adminId) {
        // 释放当前连接
        String clientSessionId = activeConnections.get(adminId);
        if (clientSessionId != null) {
            releaseConnection(adminId, clientSessionId);
        }
        
        adminSessions.remove(adminId);
        broadcastToAdmins(new Message(Message.MessageType.SYSTEM_MESSAGE, "系统", 
                "服务端用户 " + adminId + " 已下线"));
        
        // 广播在线管理员更新
        broadcastOnlineAdminsUpdate();
        
        logStatus();
    }
    
    /**
     * 注册客户端
     */
    public void registerClient(String sessionId, WebSocketSession session) {
        clientSessions.put(sessionId, session);
        logStatus();
    }
    
    /**
     * 注销客户端
     */
    public void unregisterClient(String sessionId) {
        // 从队列中移除
        connectionQueue.removeIf(req -> req.getClientSessionId().equals(sessionId));
        
        // 释放连接
        String adminId = clientToAdmin.get(sessionId);
        if (adminId != null) {
            releaseConnection(adminId, sessionId);
        }
        
        clientSessions.remove(sessionId);
        clientToAdmin.remove(sessionId);
        logStatus();
    }
    
    /**
     * 添加连接请求到队列
     */
    public boolean addConnectionRequest(String clientSessionId, String clientName, WebSocketSession clientSession) {
        System.out.println("=== 添加连接请求 ===");
        System.out.println("客户端会话ID: " + clientSessionId);
        System.out.println("客户端名称: " + clientName);
        System.out.println("当前队列大小: " + connectionQueue.size());
        System.out.println("当前服务端用户数量: " + adminSessions.size());
        
        // 检查客户端是否已在队列中
        boolean alreadyInQueue = connectionQueue.stream()
                .anyMatch(req -> req.getClientSessionId().equals(clientSessionId));
        
        if (alreadyInQueue) {
            System.out.println("客户端已在队列中，拒绝重复请求");
            return false;
        }
        
        ConnectionRequest request = new ConnectionRequest(clientSessionId, clientName, clientSession);
        connectionQueue.offer(request);
        totalRequests.incrementAndGet();
        
        System.out.println("连接请求已添加到队列");
        
        // 通知所有服务端用户
        Message notification = new Message(Message.MessageType.CONNECT_REQUEST, clientName, 
                "新的连接请求 - 客户端: " + clientName);
        notification.setSessionId(clientSessionId);
        
        System.out.println("准备广播给服务端用户，消息: " + notification);
        broadcastToAdmins(notification);
        
        logStatus();
        return true;
    }
    
    /**
     * 服务端用户接受连接
     */
    public boolean acceptConnection(String adminId, String clientSessionId) {
        // 检查服务端用户是否已有活跃连接
        if (activeConnections.containsKey(adminId)) {
            return false;
        }
        
        // 查找并移除请求
        ConnectionRequest request = null;
        for (Iterator<ConnectionRequest> it = connectionQueue.iterator(); it.hasNext();) {
            ConnectionRequest req = it.next();
            if (req.getClientSessionId().equals(clientSessionId)) {
                request = req;
                it.remove();
                break;
            }
        }
        
        if (request == null) {
            return false;
        }
        
        // 建立连接
        activeConnections.put(adminId, clientSessionId);
        clientToAdmin.put(clientSessionId, adminId);
        acceptedRequests.incrementAndGet();
        
        // 通知客户端连接已接受
        Message acceptMsg = new Message(Message.MessageType.CONNECT_ACCEPT, adminId, 
                "您的连接请求已被接受");
        sendToClient(clientSessionId, acceptMsg);
        
        // 通知服务端用户
        Message adminMsg = new Message(Message.MessageType.SYSTEM_MESSAGE, "系统", 
                "您已接受客户端 " + request.getClientName() + " 的连接");
        sendToAdmin(adminId, adminMsg);
        
        // 通知其他服务端用户移除该连接请求（不显示处理消息）
        Message removeRequestMsg = new Message(Message.MessageType.REMOVE_REQUEST, "系统", 
                "客户端 " + request.getClientName() + " 的连接已被处理");
        removeRequestMsg.setSessionId(clientSessionId);
        broadcastToAdmins(removeRequestMsg, adminId); // 排除当前处理请求的服务端用户
        
        logStatus();
        return true;
    }
    
    /**
     * 服务端用户拒绝连接
     */
    public boolean rejectConnection(String adminId, String clientSessionId) {
        // 查找并移除请求
        ConnectionRequest request = null;
        for (Iterator<ConnectionRequest> it = connectionQueue.iterator(); it.hasNext();) {
            ConnectionRequest req = it.next();
            if (req.getClientSessionId().equals(clientSessionId)) {
                request = req;
                it.remove();
                break;
            }
        }
        activeConnections.remove(clientSessionId);
        clientSessions.remove(clientSessionId);
        
        if (request == null) {
            return false;
        }
        
        rejectedRequests.incrementAndGet();
        
        // 通知客户端连接被拒绝
        Message rejectMsg = new Message(Message.MessageType.CONNECT_REJECT, adminId, 
                "您的连接请求被拒绝");
        sendToClient(clientSessionId, rejectMsg);
        
        // 通知服务端用户
        Message adminMsg = new Message(Message.MessageType.SYSTEM_MESSAGE, "系统", 
                "您已拒绝客户端 " + request.getClientName() + " 的连接");
        sendToAdmin(adminId, adminMsg);
        
        // 通知其他服务端用户移除该连接请求（不显示处理消息）
        Message removeRequestMsg = new Message(Message.MessageType.REMOVE_REQUEST, "系统", 
                "客户端 " + request.getClientName() + " 的连接已被处理");
        removeRequestMsg.setSessionId(clientSessionId);
        broadcastToAdmins(removeRequestMsg, adminId); // 排除当前处理请求的服务端用户
        
        logStatus();
        return true;
    }
    
    /**
     * 释放连接
     */
    public void releaseConnection(String adminId, String clientSessionId) {
        activeConnections.remove(adminId);
        clientToAdmin.remove(clientSessionId);
        clientConnectTime.remove(clientSessionId);
        
        // 通知客户端连接已释放
        Message releaseMsg = new Message(Message.MessageType.CONNECT_RELEASE, adminId, 
                "连接已释放");
        sendToClient(clientSessionId, releaseMsg);
        
        // 通知服务端用户
        Message adminMsg = new Message(Message.MessageType.SYSTEM_MESSAGE, "系统", 
                "连接已释放，可以接受新的连接请求");
        sendToAdmin(adminId, adminMsg);
        
        logStatus();
    }
    
    /**
     * 发送消息给客户端
     */
    public void sendToClient(String clientSessionId, Message message) {
        WebSocketSession session = clientSessions.get(clientSessionId);
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new org.springframework.web.socket.TextMessage(
                        new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(message)));
            } catch (IOException e) {
                System.err.println("发送消息给客户端失败: " + e.getMessage());
                // 如果发送失败，可能是连接已断开，移除会话
                clientSessions.remove(clientSessionId);
                clientToAdmin.remove(clientSessionId);
            }
        } else {
            System.err.println("客户端会话不存在或已关闭: " + clientSessionId);
            // 清理无效会话
            clientSessions.remove(clientSessionId);
            clientToAdmin.remove(clientSessionId);
        }
    }
    
    /**
     * 发送消息给服务端用户
     */
    public void sendToAdmin(String adminId, Message message) {
        WebSocketSession session = adminSessions.get(adminId);
        if (session != null && session.isOpen()) {
            try {
                session.sendMessage(new org.springframework.web.socket.TextMessage(
                        new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(message)));
            } catch (IOException e) {
                System.err.println("发送消息给服务端用户失败: " + e.getMessage());
                // 如果发送失败，可能是连接已断开，移除会话
                adminSessions.remove(adminId);
                // 释放该服务端用户的所有连接
                String connectedClient = activeConnections.remove(adminId);
                if (connectedClient != null) {
                    clientToAdmin.remove(connectedClient);
                }
            }
        } else {
            System.err.println("服务端用户会话不存在或已关闭: " + adminId);
            // 清理无效会话
            adminSessions.remove(adminId);
            // 释放该服务端用户的所有连接
            String connectedClient = activeConnections.remove(adminId);
            if (connectedClient != null) {
                clientToAdmin.remove(connectedClient);
            }
        }
    }
    
    /**
     * 广播消息给所有服务端用户
     */
    public void broadcastToAdmins(Message message) {
        broadcastToAdmins(message, null);
    }

    /**
     * 广播消息给所有客户端用户
     */
    public void broadcastToClient(Message message) {
        broadcastToClient(message, null);
    }
    
    /**
     * 广播消息给所有服务端用户（排除指定用户）
     */
    public void broadcastToAdmins(Message message, String excludeAdminId) {
        List<String> invalidAdmins = new ArrayList<>();
        AtomicInteger sentCount = new AtomicInteger(0);
        
        System.out.println("=== 广播消息 ===");
        System.out.println("消息类型: " + message.getType());
        System.out.println("消息内容: " + message.getContent());
        System.out.println("排除用户: " + excludeAdminId);
        System.out.println("总服务端用户数: " + adminSessions.size());
        
        adminSessions.forEach((adminId, session) -> {
            if (!adminId.equals(excludeAdminId)) {
                if (session.isOpen()) {
                    try {
                        session.sendMessage(new org.springframework.web.socket.TextMessage(
                                new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(message)));
                        sentCount.incrementAndGet();
                        System.out.println("成功发送给服务端用户: " + adminId);
                    } catch (IOException e) {
                        System.err.println("广播消息给服务端用户失败: " + e.getMessage());
                        invalidAdmins.add(adminId);
                    }
                } else {
                    System.err.println("服务端用户会话已关闭: " + adminId);
                    invalidAdmins.add(adminId);
                }
            } else {
                System.out.println("跳过排除的服务端用户: " + adminId);
            }
        });
        
        System.out.println("成功发送给 " + sentCount.get() + " 个服务端用户");
        System.out.println("=================");
        
        // 清理无效的服务端用户会话
        for (String adminId : invalidAdmins) {
            adminSessions.remove(adminId);
            // 释放该服务端用户的所有连接
            String connectedClient = activeConnections.remove(adminId);
            if (connectedClient != null) {
                clientToAdmin.remove(connectedClient);
            }
        }
    }

    /**
     * 广播消息给所有客户端用户
     */
    public void broadcastToClient(Message message, String excludeClientId) {
        List<String> invalidClients = new ArrayList<>();
        AtomicInteger sentCount = new AtomicInteger(0);

        System.out.println("=== 广播消息 ===");
        System.out.println("消息类型: " + message.getType());
        System.out.println("消息内容: " + message.getContent());
        System.out.println("排除用户: " + excludeClientId);
        System.out.println("总客户端用户数: " + clientSessions.size());

        clientSessions.forEach((clientId, session) -> {
            if (!clientId.equals(excludeClientId)) {
                if (session.isOpen()) {
                    try {
                        session.sendMessage(new org.springframework.web.socket.TextMessage(
                                new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(message)));
                        sentCount.incrementAndGet();
                        System.out.println("成功发送给服务端用户: " + clientId);
                    } catch (IOException e) {
                        System.err.println("广播消息给客户端用户失败: " + e.getMessage());
                        invalidClients.add(clientId);
                    }
                } else {
                    System.err.println("客户端用户会话已关闭: " + clientId);
                    invalidClients.add(clientId);
                }
            } else {
                System.out.println("跳过排除的客户端用户: " + clientId);
            }
        });

        System.out.println("成功发送给 " + sentCount.get() + " 个客户端用户");
        System.out.println("=================");

        // 清理无效的服务端用户会话
        for (String client : invalidClients) {
            clientSessions.remove(client);
            // 释放该服务端用户的所有连接
            String connectedClient = activeConnections.remove(client);
            if (connectedClient != null) {
                clientToAdmin.remove(connectedClient);
            }
        }
    }


    /**
     * 获取连接队列
     */
    public List<ConnectionRequest> getConnectionQueue() {
        return new ArrayList<>(connectionQueue);
    }
    
    /**
     * 获取活跃连接
     */
    public Map<String, String> getActiveConnections() {
        return new HashMap<>(activeConnections);
    }
    
    /**
     * 获取统计信息
     */
    public Map<String, Object> getStatistics() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalRequests", totalRequests.get());
        stats.put("acceptedRequests", acceptedRequests.get());
        stats.put("rejectedRequests", rejectedRequests.get());
        stats.put("queueSize", connectionQueue.size());
        stats.put("activeConnections", activeConnections.size());
        stats.put("adminCount", adminSessions.size());
        stats.put("clientCount", clientSessions.size());
        return stats;
    }
    
    /**
     * 获取服务端用户列表
     */
    public List<String> getAdminList() {
        return new ArrayList<>(adminSessions.keySet());
    }
    
    /**
     * 获取在线管理员列表
     */
    public List<String> getOnlineAdmins() {
        return new ArrayList<>(adminSessions.keySet());
    }
    
    /**
     * 检查服务端用户是否在线
     */
    public boolean isAdminOnline(String adminId) {
        return adminSessions.containsKey(adminId);
    }
    
    /**
     * 检查客户端是否在线
     */
    public boolean isClientOnline(String clientSessionId) {
        return clientSessions.containsKey(clientSessionId);
    }
    
    /**
     * 记录状态日志
     */
    private void logStatus() {
        System.out.println("=== 连接状态 ===");
        System.out.println("服务端用户数量: " + adminSessions.size());
        System.out.println("客户端数量: " + clientSessions.size());
        System.out.println("队列中的请求: " + connectionQueue.size());
        System.out.println("活跃连接: " + activeConnections.size());
        System.out.println("=================");
    }
    
    /**
     * 获取负载最低的服务端用户
     */
    public String getLeastLoadedAdmin() {
        return adminLoad.entrySet().stream()
                .min(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(null);
    }
    
    /**
     * 更新服务端用户负载
     */
    public void updateAdminLoad(String adminId, int load) {
        adminLoad.put(adminId, load);
    }
    
    /**
     * 获取服务端用户负载
     */
    public int getAdminLoad(String adminId) {
        return adminLoad.getOrDefault(adminId, 0);
    }
    
    /**
     * 检查服务端用户是否可用
     */
    public boolean isAdminAvailable(String adminId) {
        WebSocketSession session = adminSessions.get(adminId);
        if (session == null || !session.isOpen()) {
            return false;
        }
        
        // 检查最后活动时间（5分钟内无活动则视为不可用）
        Long lastActivity = adminLastActivity.get(adminId);
        if (lastActivity != null && System.currentTimeMillis() - lastActivity > 300000) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 更新服务端用户活动时间
     */
    public void updateAdminActivity(String adminId) {
        adminLastActivity.put(adminId, System.currentTimeMillis());
    }
    
    /**
     * 获取可用服务端用户列表
     */
    public List<String> getAvailableAdmins() {
        return adminSessions.keySet().stream()
                .filter(this::isAdminAvailable)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取连接统计信息
     */
    public Map<String, Object> getDetailedStatistics() {
        Map<String, Object> stats = getStatistics();
        stats.put("maxConcurrentConnections", maxConcurrentConnections.get());
        stats.put("totalConnections", totalConnections.get());
        stats.put("availableAdmins", getAvailableAdmins().size());
        stats.put("averageLoad", adminLoad.values().stream()
                .mapToInt(Integer::intValue)
                .average()
                .orElse(0.0));
        return stats;
    }
    
    /**
     * 获取服务端用户会话
     */
    public Map<String, WebSocketSession> getAdminSessions() {
        return new HashMap<>(adminSessions);
    }
    
    /**
     * 获取客户端会话
     */
    public Map<String, WebSocketSession> getClientSessions() {
        return new HashMap<>(clientSessions);
    }
    
    /**
     * 广播在线管理员更新
     */
    private void broadcastOnlineAdminsUpdate() {
        List<String> onlineAdmins = getOnlineAdmins();
        Message adminListMsg = new Message(Message.MessageType.ONLINE_ADMINS, "系统", "");
        adminListMsg.setAdmins(onlineAdmins);
        
        // 广播给所有服务端用户
        broadcastToAdmins(adminListMsg);
        System.out.println("广播在线管理员更新: " + onlineAdmins);
    }
    
    /**
     * 清理所有会话
     */
    public void clearAllSessions() {
        System.out.println("=== 清理所有会话 ===");
        
        // 清理服务端用户会话
        adminSessions.clear();
        System.out.println("已清理服务端用户会话");
        
        // 清理客户端会话
        clientSessions.clear();
        System.out.println("已清理客户端会话");
        
        // 清理连接队列
        connectionQueue.clear();
        System.out.println("已清理连接队列");
        
        // 清理活跃连接
        activeConnections.clear();
        System.out.println("已清理活跃连接");
        
        // 清理反向映射
        clientToAdmin.clear();
        System.out.println("已清理反向映射");
        
        // 清理活动时间记录
        adminLastActivity.clear();
        System.out.println("已清理活动时间记录");
        
        // 清理负载信息
        adminLoad.clear();
        System.out.println("已清理负载信息");
        
        // 清理可用管理员队列
        availableAdmins.clear();
        System.out.println("已清理可用管理员队列");
        
        // 重置统计信息
        totalRequests.set(0);
        acceptedRequests.set(0);
        rejectedRequests.set(0);
        maxConcurrentConnections.set(0);
        totalConnections.set(0);
        System.out.println("已重置统计信息");
        
        System.out.println("=== 所有会话清理完成 ===");
    }

    public Map<String, String> getClientConnectTime() {
        return clientConnectTime;
    }

    public void addTerminalAndSessionMap(String key,String value){
        terminalAndSessionMap.put(key,value);
    }
    public void removeTerminalAndSessionMap(String key){
        terminalAndSessionMap.remove(key);
    }
}
